package com.wayhome.srpingbootmybatis.policy.bo.imlpl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.wayhome.srpingbootmybatis.config.CSPService;
import com.wayhome.srpingbootmybatis.constant.BusinessConst;
import com.wayhome.srpingbootmybatis.excelListener.PolicyDocListener;
import com.wayhome.srpingbootmybatis.exception.CustomerException;
import com.wayhome.srpingbootmybatis.policy.bo.PolicyDocBO;
import com.wayhome.srpingbootmybatis.policy.dao.PolicyDocDao;
import com.wayhome.srpingbootmybatis.policy.dto.*;
import com.wayhome.srpingbootmybatis.policy.enums.PolicyTypeEnum;
import com.wayhome.srpingbootmybatis.speacecase.HeadContentCellStyle;
import com.wayhome.srpingbootmybatis.utils.DateUtils;
import com.wayhome.srpingbootmybatis.utils.ZipUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PolicyDocBOImpl implements PolicyDocBO {

    @Resource
    private PolicyDocDao policyDocDao;

    @Value("${cos.endpoint}")
    private String endpoint;

    @Resource
    private CSPService cspService;

    public static final String BUCKET = "policy-doc";
    public static final String OPT_PATH = "/Users/liangcai/Desktop/policy_file";

    @Override
    public Boolean insertPolicyDoc(PolicyDocDTO policyDocDTO) throws Exception {

        //检查必填参数
        checkInsertParam(policyDocDTO);

        //设置默认参数
        policyDocDTO.setDefaultInsertParam();
        Boolean insertResult = policyDocDao.insertPolicyDoc(policyDocDTO);
        if (insertResult && Objects.nonNull(policyDocDTO.getFiles()) && policyDocDTO.getFiles().length > 0) {
            ReqPolicyDocFileDTO reqPolicyDocFileDTO = new ReqPolicyDocFileDTO();
            reqPolicyDocFileDTO.setPolicyDocId(policyDocDTO.getId());
            reqPolicyDocFileDTO.setFiles(policyDocDTO.getFiles());
            saveUploadDocFile(reqPolicyDocFileDTO);
        }
        return insertResult;
    }

    @Override
    public List<PolicyDocDTO> queryList(ReqPolicyDocDTO reqPolicyDocDTO) throws Exception {
        if (Objects.isNull(reqPolicyDocDTO)) {
            throw new CustomerException("请求参数不能为空");
        }
        return policyDocDao.queryPolicyDocList(reqPolicyDocDTO);
    }

    @Override
    public Boolean updateDoc(PolicyDocDTO policyDocDTO) throws Exception {
        if (Objects.isNull(policyDocDTO)) {
            throw new CustomerException("请求参数不能为空");
        }
        if (Objects.isNull(policyDocDTO.getId())) {
            throw new CustomerException("要更新政策文件的主键不能为空");
        }
        if (!CollectionUtils.isEmpty(policyDocDTO.getDelFileIds())) {
            policyDocDao.batchInvalidateDocFile(policyDocDTO.getDelFileIds());
        }
        List<PolicyDocFileDTO> policyDocFileDTOS = policyDocDao.queryDocFileList(policyDocDTO.getId());
        if (CollectionUtils.isEmpty(policyDocFileDTOS)) {
            policyDocDTO.setUploadFlag("0");
        }
        setDefaultUpdateParam(policyDocDTO);
        return policyDocDao.updatePolicyDoc(policyDocDTO);
    }

    @Override
    public Boolean saveUploadDocFile(ReqPolicyDocFileDTO request) throws Exception {
        if (Objects.isNull(request)) {
            throw new CustomerException("请求参数不能为空");
        }
        if (Objects.isNull(request.getPolicyDocId())) {
            throw new CustomerException("政策id不能为空");
        }
        if (Objects.isNull(request.getFiles()) || request.getFiles().length == 0) {
            throw new CustomerException("请上传政策相关文件");
        }
        PolicyDocDTO policyDocDTO = policyDocDao.queryPolicyDocById(request.getPolicyDocId());
        if (Objects.isNull(policyDocDTO)) {
            throw new CustomerException("没找到相关政策，请检查后参数是否正确");
        }
        if (!"1".equals(policyDocDTO.getValiFlag())) {
            throw new CustomerException("该政策已设置成无效状态");
        }

        //上传的文件
        MultipartFile[] files = request.getFiles();
        List<PolicyDocFileDTO> list = new ArrayList<>();
        for (MultipartFile file : files) {
            String filename = file.getOriginalFilename();
            PolicyDocFileDTO policyDocFileDTO = new PolicyDocFileDTO();
            policyDocFileDTO.setPolicyDocId(request.getPolicyDocId());
            //上传文件
            String filePath = cspService.uploadFile(file, BUCKET, filename, BusinessConst.HEBEI_CODE);
            filePath = filePath.replace(endpoint, "");
            policyDocFileDTO.setFilePath(filePath);
            policyDocFileDTO.setFileName(filename);
            policyDocFileDTO.setDefaultInsertParam();
            list.add(policyDocFileDTO);
        }
        Boolean insertResult = policyDocDao.batchInsertPolicyDocFile(list);
        if (insertResult) {
            PolicyDocDTO updateDoc = new PolicyDocDTO();
            updateDoc.setId(request.getPolicyDocId());
            updateDoc.setUploadFlag("1");
            policyDocDao.updatePolicyDoc(updateDoc);
        }
        return insertResult;
    }

    @Override
    public PolicyDocDTO queryDocDetail(ReqPolicyDocDTO request) throws Exception {
        if (Objects.isNull(request)) {
            throw new CustomerException("请求参数不能为空");
        }
        if (Objects.isNull(request.getId())) {
            throw new CustomerException("政策id不能为空");
        }
        PolicyDocDTO policyDocDTO = policyDocDao.queryPolicyDocById(request.getId());
        if (Objects.isNull(policyDocDTO)) {
            throw new CustomerException("未找到相关的政策信息");
        }
        List<PolicyDocFileDTO> policyDocFileDTOS = policyDocDao.queryDocFileList(policyDocDTO.getId());
        if (!CollectionUtils.isEmpty(policyDocFileDTOS)) {
            List<SimplePolicyDocFile> docFileList = new ArrayList<>(policyDocFileDTOS.size());
            for (PolicyDocFileDTO policyDocFileDTO : policyDocFileDTOS) {
                SimplePolicyDocFile simplePolicyDocFile = new SimplePolicyDocFile();
                BeanUtils.copyProperties(policyDocFileDTO, simplePolicyDocFile);
                docFileList.add(simplePolicyDocFile);
                policyDocDTO.setFileList(docFileList);
            }
        }
        return policyDocDTO;
    }

    @Override
    public Boolean deleteDoc(PolicyDocDTO request) throws Exception {
        if (Objects.isNull(request)) {
            throw new CustomerException("请求参数不能为空");
        }
        if (Objects.isNull(request.getId())) {
            throw new CustomerException("政策id不能为空");
        }
        request.setValiFlag("0");
        setDefaultUpdateParam(request);
        return policyDocDao.updatePolicyDoc(request);
    }

    @Override
    public void downloadPolicyFile(ReqPolicyDocDTO reqPolicyDocDTO) throws Exception {

        //step1:查出所有要导出的政策
        List<PolicyDocDTO> policyDocDTOS = queryList(reqPolicyDocDTO);
        if (CollectionUtils.isEmpty(policyDocDTOS)) {
            throw new CustomerException("未查询到要下载的政策信息");
        }

        //step2:查出所有要导出的政策文件
        List<Long> policyIds = policyDocDTOS.stream().map(PolicyDocDTO::getId).collect(Collectors.toList());
        List<PolicyDocFileDTO> policyDocFileDTOS = policyDocDao.queryDocFileListByPolicyDocIds(policyIds);

        //step3:将所有要导出的文件转化成自己想要实体
        List<PolicyDownloadDTO> downloadList = new ArrayList<>();
        for (PolicyDocDTO policyDocDTO : policyDocDTOS) {
            PolicyDownloadDTO downloadDTO = cover2DownloadEntity(policyDocDTO, policyDocFileDTOS);
            downloadList.add(downloadDTO);
        }

        //step4:将要导出的政策按照区划分好包
        Map<String, List<PolicyDownloadDTO>> admdvsGroup = downloadList.stream().collect(Collectors.groupingBy(PolicyDownloadDTO::getAdmdvs));
        for (Map.Entry<String, List<PolicyDownloadDTO>> stringListEntry : admdvsGroup.entrySet()) {
            String admdvs = stringListEntry.getKey();
            List<PolicyDownloadDTO> list = stringListEntry.getValue();
            fileClassification(admdvs, list);
        }
        //导出压缩包
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition",
                "attachment; filename=export.zip");
        try{
            ZipUtils.zipFolder(OPT_PATH, response.getOutputStream());

        }catch (Exception e) {
            throw e;
        } finally {
          File dir = new File(OPT_PATH);
          if (dir.exists()) {
              FileUtils.deleteDirectory(dir);
          }
        }
    }

    //将政策信息转成要导出的实体
    private PolicyDownloadDTO cover2DownloadEntity(PolicyDocDTO request, List<PolicyDocFileDTO> policyDocFileDTOS) {
        PolicyDownloadDTO downloadDTO = new PolicyDownloadDTO();
        BeanUtils.copyProperties(request, downloadDTO);
        String policyTypeName = PolicyTypeEnum.getMsgByCode(request.getPolicyType());
        //类别
        downloadDTO.setPolicyTypeName(policyTypeName);
        //是否补充文件
        downloadDTO.setSuptFlagStr("1".equals(request.getSuptFlag()) ? "是" : "否");
        //是否在有效期内
        downloadDTO.setEffectiveFlagStr("1".equals(request.getEffectiveFlag()) ? "是" : "否");
        //设置时间
        if (Objects.nonNull(request.getPubDate())) {
            Date pubDate = request.getPubDate();
            String date2Str = DateUtils.date2Str(pubDate, "yyyy-MM-dd");
            downloadDTO.setPubDateStr(date2Str);
        }
        //设置区划
        String admdvs = BusinessConst.HEBEI_CODE.equals(request.getAdmdvs()) ? request.getAdmdvs() : getCityAdmdvs(request.getAdmdvs());
        downloadDTO.setAdmdvs(admdvs);
        if (!CollectionUtils.isEmpty(policyDocFileDTOS)) {
            List<PolicyDocFileDTO> collect = policyDocFileDTOS.stream().filter(item -> item.getPolicyDocId().equals(request.getId())).collect(Collectors.toList());
            downloadDTO.setFileList(collect);
        }
        return downloadDTO;
    }

    private void fileClassification(String admdvs, List<PolicyDownloadDTO> list) throws Exception {
        String optFilePath = OPT_PATH + "/" + admdvs + "/政策文件列表.xlsx";
        File policyDocFile = new File(optFilePath);
        if (!policyDocFile.getParentFile().exists()) {
            policyDocFile.getParentFile().mkdirs();
        }
        EasyExcel.write(optFilePath,PolicyDownloadDTO.class)
                .registerWriteHandler(HeadContentCellStyle.myHorizontalCellStyleStrategy())
                .registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
                .sheet("政策文件").doWrite(list);

        for (PolicyDownloadDTO downloadDTO : list) {
            for (PolicyDocFileDTO item : downloadDTO.getFileList()) {
                InputStream fileStream = cspService.getFileStream(BUCKET, item.getFileName(), admdvs);
                String optUploadFilePath = OPT_PATH + "/" + admdvs + "/" + item.getFileName();
                try (OutputStream outputStream = new FileOutputStream(optUploadFilePath)) {
                    byte[] buffer = new byte[8192];
                    int bytesRead;
                    while ((bytesRead = fileStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                } catch (IOException e) {
                    log.info("写入【{}】政策的上传文件【{}】时报错",downloadDTO.getDocName(),item.getFileName());
                    e.printStackTrace();
                }
            }
        }
    }

    //检查参数
    private void checkInsertParam(PolicyDocDTO request) throws Exception {
        if (Objects.isNull(request)) {
            throw new CustomerException("请求参数不能为空");
        }
        if (StringUtils.isEmpty(request.getPolicyType())) {
            throw new CustomerException("文件类别");
        }
        if (StringUtils.isEmpty(request.getPolicyYear())) {
            throw new CustomerException("年份不能为空");
        }
        if (StringUtils.isEmpty(request.getDocName())) {
            throw new CustomerException("文件名称不能为空");
        }
        if (Objects.isNull(request.getPubDate())) {
            throw new CustomerException("具体发文时间不能为空");
        }
        if (StringUtils.isEmpty(request.getPubDept())) {
            throw new CustomerException("发文单位不能为空");
        }
        if (StringUtils.isEmpty(request.getDocLmtPeriod())) {
            throw new CustomerException("文件有效时限不能为空");
        }
        if (StringUtils.isEmpty(request.getEffectiveFlag())) {
            throw new CustomerException("是否在有效期内不能为空");
        }
        if (StringUtils.isEmpty(request.getSuptFlag())) {
            request.setSuptFlag("0");
        }
    }



    //设置更新时的默认参数
    private void setDefaultUpdateParam(PolicyDocDTO policyDocDTO) {
        Date now = new Date();
        //更新时间
        policyDocDTO.setUpdtTime(now);
        //经办时间
        policyDocDTO.setOptTime(now);

        String userAcct = "system";
        String userName = "系统";
        String optinNo = "S13000010001";

        //经办人
        policyDocDTO.setOpterId(userAcct);
        policyDocDTO.setOpterName(userName);
        policyDocDTO.setOptinsNo(optinNo);

    }

    /**
     * 统筹区编码转换
     * @param code
     * @return
     */
    private String getCityAdmdvs(String code) {

        if (BusinessConst.XINJI_CODE.equals(code) ||
                BusinessConst.DINGZHOU_CODE.equals(code) ||
                BusinessConst.HUAYOU_CODE.equals(code) ||
                BusinessConst.SHITIE_CODE.equals(code) ||
                BusinessConst.DIANLI_CODE.equals(code)){
            return code;
        }else{
            return code.substring(0,4) + "00";
        }

    }
}
